#include "StdAfx.h"
#include "http_service.h"

#pragma comment(lib, "httpapi.lib")

CHttpService::CHttpService()
{
	m_thread = NULL;
	m_request_queue  = NULL;
	m_request_buffer = NULL;
	m_request_buffer_size = 4096;
}

BOOL CHttpService::Create(INT port, CHttpServiceListener *listener)
{
	ULONG ret;
	WCHAR url[1024];
	HTTPAPI_VERSION version = HTTP_VERSION_1_0;
	swprintf(url, 1024, L"http://*:%d/", port);
	ret = HttpInitialize(version,HTTP_INITIALIZE_SERVER,NULL);
	if(ret != NO_ERROR)
	{
		TRACE("HttpInitialize error(%u)!\r\n", ret);
		return FALSE;
	}

	ret = HttpCreateHttpHandle(&m_request_queue, 0);
	if(ret != NO_ERROR)
	{
		TRACE("HttpCreateHttpHandle error(%u)!\n", ret);
		HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);
		return FALSE;
	}
	ret = HttpAddUrl(m_request_queue, url, NULL);
	if(ret != NO_ERROR)
	{
		TRACE("HttpAddUrl error(%u)!\n", ret);
		CloseHandle(m_request_queue);
		HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);
		m_request_queue = NULL;
		return FALSE;
	}
	m_request_buffer = (LPBYTE)malloc(m_request_buffer_size);
	m_listener = listener;
	m_thread = AfxBeginThread(RecvRequestThread, this);
	return TRUE;
}

BOOL CHttpService::Delete(void)
{
	if(m_request_queue)
	{
		CloseHandle(m_request_queue);
		HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);
		m_request_queue = NULL;
	}
	if(m_request_buffer)
	{
		free(m_request_buffer);
		m_request_buffer = NULL;
	}
	if(m_thread)
	{
		m_thread->Delete();
		m_thread = NULL;
	}
	return TRUE;
}

BOOL CHttpService::SendRequestResp(PHTTP_REQUEST request, INT status, LPCSTR reason, LPCSTR content_type, LPCSTR text, DWORD text_size)
{
	HTTP_RESPONSE   resp;
	HTTP_DATA_CHUNK chunk;
	DWORD           ret;
	DWORD           sent;

	RtlZeroMemory(&resp, sizeof(resp));
	resp.StatusCode   = status;
	resp.pReason      = reason;
	resp.ReasonLength = (USHORT)strlen(reason);
	resp.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = content_type;
	resp.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen(content_type);
	resp.EntityChunkCount = 1;
	resp.pEntityChunks    = &chunk;

	chunk.DataChunkType = HttpDataChunkFromMemory;
	chunk.FromMemory.pBuffer = (PVOID)text;
	chunk.FromMemory.BufferLength = text_size;

	ret = HttpSendHttpResponse(m_request_queue, request->RequestId, 0, &resp, NULL,	&sent, NULL, 0, NULL, NULL); 
	if(ret != NO_ERROR)
	{
		TRACE(L"HttpSendHttpResponse error(%u)!\n", ret);
		return FALSE;
	}
	return TRUE;
}

BOOL CHttpService::RecvRequestBody(PHTTP_REQUEST request, LPSTR text, DWORD text_size)
{
	DWORD read;
	DWORD ret;
	read = 0;
	ret = HttpReceiveRequestEntityBody(m_request_queue, request->RequestId, 0, text, text_size - 1, &read, NULL);
	text[read] = 0;
	return ret == ERROR_HANDLE_EOF;
}

UINT CHttpService::RecvRequestThread(LPVOID param)
{
	CHttpService *self;
	self = (CHttpService *)param;
	self->DoReceiveRequests();
	Sleep(INFINITE);
	return 0;
}

BOOL CHttpService::DoReceiveRequests(void)
{
    ULONG         ret;
    DWORD         bytes_read;
    PHTTP_REQUEST request;
    request = (PHTTP_REQUEST)m_request_buffer;
    while(1)
    {
        RtlZeroMemory(request,m_request_buffer_size);
        ret = HttpReceiveHttpRequest(m_request_queue,HTTP_NULL_ID,0,request,m_request_buffer_size,&bytes_read,NULL);
		if(ret == NO_ERROR)
		{
			m_listener->OnRecvRequest(this,request);
			continue;
		}
		TRACE("HttpReceiveHttpRequest error(%u)!\r\n", ret);
		if(ret == ERROR_OPERATION_ABORTED)
		{
			return FALSE;
		}
		if(ret == ERROR_INVALID_HANDLE)
		{
			return FALSE;
		}
	}
	return TRUE;
}

BOOL CHttpService::GetRemoteAddr(PHTTP_REQUEST request, CString &text)
{
	PSOCKADDR_IN addr = (PSOCKADDR_IN)request->Address.pRemoteAddress;
	text.Format("%d.%d.%d.%d", addr->sin_addr.S_un.S_un_b.s_b1, addr->sin_addr.S_un.S_un_b.s_b2, addr->sin_addr.S_un.S_un_b.s_b3,addr->sin_addr.S_un.S_un_b.s_b4);
	return TRUE;
}
